﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace SAI.RouteFinding
{
    class Maze
    {
        private int _rows;
        private int _columns;
        private RouteNode[,] _map;
        private RouteNode _start;
        private RouteNode _goal;
        private int _nodes;
        private int _solutionLength;
        private const char _unpassableChar1 = 'T';
        private const char _unpassableChar2 = '@';
        public Maze(string mapName, int scenario)
        {
            _solutionLength = 0;
            _start = null;
            _goal = null;
            _nodes = 1;
            string[] map;
            string[] scenarios;
            map = File.ReadAllLines("../../RouteFinding/Maps/" + mapName);
            
            readMapDimensions(map);
            createNodes(map);
            setChildren();
            scenarios = File.ReadAllLines("../../RouteFinding/Scenarios/" + mapName + ".scen");
            setStartGoalNodes(scenarios, scenario);

        }

        public RouteNode Start { get { return _start; } }
        public RouteNode Goal { get { return _goal; } }
        public int Nodes { get { return _nodes; } }
        public int SolutionLength { get { return _solutionLength; } }

        private void readMapDimensions(string[] map)
        {
            string[] height = map[1].Split(' ');
            string[] width = map[2].Split(' ');
            _rows = int.Parse(height[1]);
            _columns = int.Parse(width[1]);
            _map = new RouteNode[_rows, _columns];
        }

        private void createNodes(string[] map)
        {
            for (int rowIndex = 4; rowIndex < map.Length; rowIndex++)
            {
                char[] rowCells = map[rowIndex].ToCharArray();

                for(int columnIndex = 0; columnIndex < _columns; columnIndex++)
                {
                    char cell = rowCells[columnIndex];
                    if (!cell.Equals(_unpassableChar1) && !cell.Equals(_unpassableChar2))
                    {
                        RouteNode node = new RouteNode((rowIndex - 4).ToString() + "," + columnIndex);
                        node.Column = columnIndex;
                        node.Row = rowIndex - 4;
                        _map[rowIndex - 4, columnIndex] = node;
                        _nodes++;
                    }
                }
            }
        }


        private void setChildren()
        {
            for (int rowIndex = 0; rowIndex < _rows; rowIndex++)
            {
                for (int columnIndex = 0; columnIndex < _columns; columnIndex++)
                {
                    RouteNode currentNode = _map[rowIndex, columnIndex];
                    if (currentNode == null)
                        continue;
                    RouteNode closeNode1, closeNode2, closeNode3, closeNode4 = null;
                    RouteNode closeNode5, closeNode6, closeNode7, closeNode8 = null;
                    
                    /*if (passableNode(rowIndex - 1, columnIndex - 1))
                    {
                        closeNode1 = _map[rowIndex - 1, columnIndex - 1];
                        currentNode.OutNeighbors.Add(closeNode1);
                    }*/
                    if (passableNode(rowIndex - 1, columnIndex))
                    {
                        closeNode2 = _map[rowIndex - 1, columnIndex];
                        currentNode.OutNeighbors.Add(closeNode2);
                    }
                    /*if (passableNode(rowIndex - 1, columnIndex + 1))
                    {
                        closeNode3 = _map[rowIndex - 1, columnIndex + 1];
                        currentNode.OutNeighbors.Add(closeNode3);
                    }*/
                    if (passableNode(rowIndex, columnIndex - 1))
                    {
                        closeNode4 = _map[rowIndex, columnIndex - 1];
                        currentNode.OutNeighbors.Add(closeNode4);
                    }
                    if (passableNode(rowIndex, columnIndex + 1))
                    {
                        closeNode5 = _map[rowIndex, columnIndex + 1];
                        currentNode.OutNeighbors.Add(closeNode5);
                    }
                    /*if (passableNode(rowIndex + 1, columnIndex - 1))
                    {
                        closeNode6 = _map[rowIndex + 1, columnIndex - 1];
                        currentNode.OutNeighbors.Add(closeNode6);
                    }*/
                    if (passableNode(rowIndex + 1, columnIndex))
                    {
                        closeNode7 = _map[rowIndex + 1, columnIndex];
                        currentNode.OutNeighbors.Add(closeNode7);
                    }
                    /*if (passableNode(rowIndex + 1, columnIndex + 1))
                    {
                        closeNode8 = _map[rowIndex + 1, columnIndex + 1];
                        currentNode.OutNeighbors.Add(closeNode8);
                    }*/
                }
            }
        }

        private bool passableNode(int row, int column)
        {
            return row >= 0 && row < _rows && column >= 0 && column < _columns && _map[row, column] != null;
        }

        //Bucket,map,map width,map height,start x-coordinate,start y-coordinate,goal x-coordinate,goal y-coordinate,optimal length
        private void setStartGoalNodes(string[] scenarios, int numberOfScenario)
        {
            string[] scenario = scenarios[numberOfScenario].Split('\t');
            int startRow = int.Parse(scenario[5]);
            int startColumn = int.Parse(scenario[4]);
            int goalRow = int.Parse(scenario[7]);
            int goalColumn = int.Parse(scenario[6]);
            

            _start = _map[startRow, startColumn];
            _goal = _map[goalRow, goalColumn];
            if (_start == null || _goal == null)
                Console.WriteLine("Error in scenario: start point or goal point aren't reachable");
        }

        public void printSolution()
        {
            Dictionary<string, RouteNode> sol = new Dictionary<string,RouteNode>();
            RouteNode parent = _goal;
            StreamWriter solutionWriter = new StreamWriter("solution.txt");
            while (parent.Parent != null && parent.Row != -1)
            {
                sol.Add(parent.ID, parent);
                parent = (RouteNode)parent.Parent;
            }
            _solutionLength = sol.Count;
            for (int i = 0; i < _rows; i++)
            {
                for (int j = 0; j < _columns; j++)
                {
                    RouteNode node = _map[i, j];
                    
                    if (node == null)
                        solutionWriter.Write("T");
                    else if (node.ID.Equals(_start.ID))
                        solutionWriter.Write("S");
                    else if (node.ID.Equals(_goal.ID))
                        solutionWriter.Write("G");
                    else if (sol.ContainsKey(node.ID))
                        solutionWriter.Write("X");
                    else
                        solutionWriter.Write(".");
                }
                solutionWriter.WriteLine();
            }
            solutionWriter.Close();
        }
    }
}
